<?php

class MsggUcpaas extends MsggChannelBase
{

    //2 minutes
    const SMS_TIMEOUT_TIME = 10 * 60;
    const REST_URL = 'https://api.ucpaas.com';
    const SOFT_VERSION = '2014-06-30';
    const SUCCESS_RESP_CODE = '000000';
    const DEFAULT_KEY = 'default';

    const TYPE_SMS = 'sms';
    const TYPE_CALL = 'call';

    const ERROR_CODE_FAIL = 1;

    private static $_conf = array();

    public static function sms($params = array(), $conf = array())
    {
        static::$_conf = $conf;
        $result = array('code' => 0, 'msg' => '', 'data' => array(), 'ext' => array());
        //replace some invalid character
        if (isset($params['param']) && is_array($params['param'])) {
            foreach ($params['param'] as $key => $param) {
                $params['param'][$key] = str_replace(',', '，', $params['param'][$key]);
                $params['param'][$key] = str_replace(['【', '】'], ['【' => '（', '】' => '）'], $params['param'][$key]);
            }
        }
        try {
            //curl api
            $url = self::getUrl(self::TYPE_SMS);
            $postdata = array(
                'templateSMS' => array(
                    'appId' => static::getConf('application_id'),
                    'to' => $params['phone'],
                    'templateId' => $params['template']['id_ucpaas'],
                    'param' => implode(',', $params['param']),
                )
            );
            $resp = self::curlApi($url, $postdata);
            $result['data'] = $resp;
            $result['ext']['id'] = empty($resp['resp']['templateSMS']['smsId']) ? null : $resp['resp']['templateSMS']['smsId'];
            $result['ext']['status'] = MsggSms::STATUS_RUNNING;
        } catch (Exception $e) {
            $result['code'] = $e->getCode();
            $result['msg'] = $e->getMessage();
            $result['ext']['status'] = MsggSms::STATUS_ERROR;
        }
        $result['ext']['class'] = self::class;
        return $result;
    }

    public static function call($params = array(), $conf = array())
    {
        static::$_conf = $conf;
        $result = array('code' => 0, 'msg' => '', 'data' => array(), 'ext' => array());
        try {
            $url = self::getUrl(self::TYPE_CALL);
            $postdata = array(
                'voiceNotify' => array(
                    'appId' => static::getConf('application_id'),
                    'type' => '1',
                    'playTimes' => '3',
                    'toSerNum' => '075512345678',
                    'to' => $params['phone'],
                    'content' => $params['media']['ext_ucpaas'],
                )
            );
            $resp = self::curlApi($url, $postdata);
            $result['data'] = $resp;
            $result['ext']['id'] = empty($resp['resp']['voiceNotify']['callId']) ? null : $resp['resp']['voiceNotify']['callId'];
            $result['ext']['status'] = MsggCall::STATUS_RUNNING;
        } catch (Exception $e) {
            //gen result
            $result['code'] = $e->getCode();
            $result['msg'] = $e->getMessage();
            $result['ext']['status'] = MsggCall::STATUS_ERROR;
        }
        //return result
        $result['ext']['class'] = self::class;
        return $result;
    }

    private static function curlApi($url, $postdata = array(), $options = array())
    {
        try {
            $headers = array(
                'Accept' => 'application/json;',
                'Content-Type' => 'application/json;charset=utf-8;',
                'Authorization' => self::getAuthor()
            );
            $try = self::getConf('try', 2);
            while ($try) {
                $try--;
                $cres = Curl::post($url, json_encode($postdata, JSON_UNESCAPED_UNICODE), $options, $headers);
                if ($cres['err']) {
                    if ($try) {
                        continue;
                    }
                    throw new Exception('CurlErr:' . $cres['err'], self::ERROR_CODE_FAIL);
                }
                if (empty($cres['content'])) {
                    if ($try) {
                        continue;
                    }
                    throw new Exception('response content empty', self::ERROR_CODE_FAIL);
                }
                if (!($resp = json_decode($cres['content'], true))) {
                    if ($try) {
                        continue;
                    }
                    throw new Exception('response content decode fail:' . $cres['content'], self::ERROR_CODE_FAIL);
                }
                $respCode = isset($resp['resp']['respCode']) ? $resp['resp']['respCode'] : 'null';
                if ($respCode != self::SUCCESS_RESP_CODE) {
                    if ($try) {
                        continue;
                    }
                    throw new Exception('response respCode abnormal:' . $cres['content'], self::ERROR_CODE_FAIL);
                }
                return $resp;
            }
        } catch (Exception $e) {
            throw new Exception($e->getMessage(), self::ERROR_CODE_FAIL);
        }
    }

    private static function getUrl($type = self::TYPE_SMS)
    {
        if (!($account_sid = static::getConf('account_sid'))) {
            throw new Exception('conf account_sid invalid', self::ERROR_CODE_FAIL);
        }
        $sig = self::getSig();
        switch ($type) {
            case self::TYPE_CALL:
                return self::REST_URL . "/" . self::SOFT_VERSION . "/Accounts/" . $account_sid . "/Calls/voiceNotify?sig=" . $sig;
                break;
            case self::TYPE_SMS:
            default:
                return self::REST_URL . "/" . self::SOFT_VERSION . "/Accounts/" . $account_sid . "/Messages/templateSMS?sig=" . $sig;
                break;
        }
    }

    private static function getSig()
    {
        if (!($account_sid = static::getConf('account_sid'))) {
            throw new Exception('conf account_sid invalid', self::ERROR_CODE_FAIL);
        }
        if (!($auth_token = static::getConf('auth_token'))) {
            throw new Exception('conf auth_token invalid', self::ERROR_CODE_FAIL);
        }
        $date = date("YmdHis");
        return strtoupper(md5($account_sid . $auth_token . $date));
    }

    private static function getAuthor()
    {
        if (!($account_sid = static::getConf('account_sid'))) {
            throw new Exception('conf account_sid invalid', self::ERROR_CODE_FAIL);
        }
        $date = date("YmdHis");
        return base64_encode($account_sid . ":" . $date);
    }

    public static function getConf($name, $default = null)
    {
        return isset(static::$_conf[$name]) ? static::$_conf[$name] : $default;
    }

    public static function hookSms()
    {
        header('Content-type:application/xml');
        $params = json_decode(json_encode(simplexml_load_string(file_get_contents('php://input'))), true);
        if (!($ext_id = empty($params['smsid']) ? null : (string)$params['smsid'])) {
            return;
        }
        Yii::log(json_encode($params), CLogger::LEVEL_INFO, 'ucpaas.hook');
        if (($status = (!isset($params['status']) ? null : (string)$params['status'])) === null) {
            return;
        }
        if (!($ext_status = self::mapStatus(self::TYPE_SMS, $status))) {
            return;
        }
        if (MsggChannelLog::updateExtStatus($ext_id, $ext_status, $params)) {
            echo '<?xml version="1.0" encoding="UTF-8"?><response><retcode>0</retcode></response>';
        }
    }

    public static function hookCall()
    {
        header('Content-type:application/xml');
        $params = json_decode(json_encode(simplexml_load_string(file_get_contents('php://input'))), true);
        if (!($ext_id = empty($params['callid']) ? null : (string)$params['callid'])) {
            return;
        }
        if (!($status = empty($params['state']) ? null : (string)$params['state'])) {
            return;
        }
        if (!($ext_status = self::mapStatus(self::TYPE_CALL, $status))) {
            return;
        }
        if (MsggChannelLog::updateExtStatus($ext_id, $ext_status, $params)) {
            echo '<?xml version="1.0" encoding="UTF-8"?><response><retcode>0</retcode></response>';
        }
    }

    private static function mapStatus($type, $status)
    {
        $resStatus = null;
        switch ($type) {
            case self::TYPE_SMS:
                switch ($status) {
                    case '0':
                        $resStatus = MsggSms::STATUS_SUCCESS;
                        break;
                    case '7':
                        $resStatus = MsggSms::STATUS_FAILURE_OVERRATE;
                        break;
                    case '1':
                    case '4':
                    case '5':
                    case '6':
                    case '8':
                        $resStatus = MsggSms::STATUS_FAILURE;
                        break;
                }
                break;
            case self::TYPE_CALL:
                switch ($status) {
                    case '0':
                        $resStatus = MsggCall::STATUS_SUCCESS;
                        break;
                    case '1':
                        $resStatus = MsggCall::STATUS_COMPLETE_TIMEOUT;
                        break;
                    case '2':
                        $resStatus = MsggCall::STATUS_COMPLETE_UNANSWERED;
                        break;
                    case '3':
                        $resStatus = MsggCall::STATUS_FAILURE;
                        break;
                }
                break;
        }
        return $resStatus;
    }

    public static function refreshStatus(MsggChannelLog $channelLog)
    {
        // TODO: Implement refreshStatus() method.
        if (!empty($channelLog) && $channelLog->type) {
            switch ($channelLog->type) {
                case MsggItem::TYPE_SMS:
                    if(time()-$channelLog->time>=self::SMS_TIMEOUT_TIME)
                    {
                        Yii::log('ucpaas sms time out', CLogger::LEVEL_INFO,   __METHOD__);
                        return MsggSms::STATUS_FAILURE;
                    }
                    return $channelLog->ext_status;
                    break;
            }
        }
        return parent::refreshStatus($channelLog);
    }
}